/************************************************************************
This file is part of java core libraries for the simpleRTJ virtual machine.

This file is covered by the GNU GPL with the following exception:
  As a special exception, the copyright holders of this library give you permission
  to link this library with independent modules to produce an executable, regardless
  of the license terms of these independent modules, and to copy and distribute the
  resulting executable under terms of your choice, provided that you also meet, for
  each linked independent module, the terms and conditions of the license of that
  module. An independent module is a module which is not derived from or based on
  this library. If you modify this library, you may extend this exception to your
  version of the library, but you are not obligated to do so. If you do not wish
  to do so, delete this exception statement from your version.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL RTJ COMPUTING BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

Copyright (c) 2000-2002 RTJ Computing Pty. Ltd. All rights reserved.
***********************************************************************/
package javax.memory;

/**
 * The instances of a SerialEEProm class can access data in the EEPROM memory
 * accessible via serial bus. <br>
 * Note: Native code routines do not provide any particular erase/write procedures as this
 * really depends on memory chips used. Software developer must modify appropriate routines
 * in the native code to implement correct programming algorithm.
 * <p>
 *
 * In order to use this class in your application follow the following steps:<br>
 *    1. Locate the SerialEEProm.c in the source/javax/memory/native directory<br>
 *    2. Copy this file into your project's native code directory and
 *       make it part of the native code building process.
 *    3. Implement programming algorithm specific to a serial EEPROM type used.
 */
public class SerialEEProm extends MemoryRegion
{
    /**
     * Creates a new SerialEEProm memory region object.
     *
     * @param start starting address of a new memory region.
     * @param length length of a new memory region.
     * @exception InvalidMemoryRegionException is thrown when the requested region
     *      is invalid, i.e. overlaps with some other memory regions or there is no
     *      physical memory at specified location.
     */
    public SerialEEProm(int start, int length) throws InvalidMemoryRegionException
    {
        super(start, length);
    }

    /**
     * Writes a <code>byte</code> into memory at current offset. Method setOffset()
     * should be called prior calling this method to setup the offset pointer.<br>
     * Offset pointer will be modified by 1 if post-increment is enabled or -1 if
     * post-decrement is enabled.
     *
     * @param value  a byte value that will be written into memory. Only lower 8 bits are written.
     * @exception RegionAddressOutOfBoundsException is thrown when trying to access data out of bounds
     *      of this memory region.
     */
    public void writeByte(int value) throws RegionAddressOutOfBoundsException
    {
        if (regStart + memOffs < regStart || regStart + memOffs >= regEnd)
            throw new RegionAddressOutOfBoundsException();

        writeByte0(regStart + memOffs, value);
        if (postIncrement)
            memOffs++;
        else if (postDecrement)
            memOffs--;
    }

    /**
     * Writes a <code>short</code> into memory at current offset. Method setOffset()
     * should be called prior calling this method to setup the offset pointer.<br>
     * Offset pointer will be modified by 2 if post-increment is enabled or -2 if
     * post-decrement is enabled.
     *
     * @param value  a short value that will be written into memory. Only lower 16 bits are written.
     * @exception RegionAddressOutOfBoundsException is thrown when trying to access data out of bounds
     *      of this memory region.
     */
    public void writeShort(int value) throws RegionAddressOutOfBoundsException
    {
        if (regStart + memOffs < regStart || regStart + memOffs >= regEnd)
            throw new RegionAddressOutOfBoundsException();

        writeByte0(regStart + memOffs, value >> 8);
        writeByte0(regStart + memOffs + 1, value);
        if (postIncrement)
            memOffs += 2;
        if (postDecrement)
            memOffs -= 2;
    }

    /**
     * Writes a <code>int</code> into memory at current offset. Method setOffset()
     * should be called prior calling this method to setup the offset pointer.<br>
     * Offset pointer will be modified by 4 if post-increment is enabled or -4 if
     * post-decrement is enabled.
     *
     * @param value  a integer value (32 bit) that will be written into memory.
     * @exception RegionAddressOutOfBounds is thrown when trying to access data out of bounds
     *      of this memory region.
     */
    public void writeInt(int value) throws RegionAddressOutOfBoundsException
    {
        if (regStart + memOffs < regStart || regStart + memOffs >= regEnd)
            throw new RegionAddressOutOfBoundsException();

        writeInt0(regStart + memOffs, value >> 24);
        writeInt0(regStart + memOffs + 1, value >> 16);
        writeInt0(regStart + memOffs + 2, value >> 8);
        writeInt0(regStart + memOffs + 3, value);
        if (postIncrement)
            memOffs += 4;
        if (postDecrement)
            memOffs -= 4;
    }

    /**
     * Writes <code>byte</code> array to the memory starting at the current offset.
     * Method setOffset() should be called prior calling this method to setup the offset pointer.<br>
     * The offset pointer will be modified by the number of bytes written if post-increment
     * or post-decrement flag is set.
     *
     * @param array a source byte array
     * @param start starting offset in the array
     * @param length number of bytes to write
     * @exception RegionAddressOutOfBoundsException is thrown when trying to access data out of bounds
     *      of this memory region.
     * @exception IndexOutOfBoundsException is thrown when trying to access array data that out of bounds
     *      of the input byte array.
     */
    public void writeBytes(byte[] array, int start, int length)
        throws RegionAddressOutOfBoundsException, IndexOutOfBoundsException
    {
        if (start + length > array.length)
            throw new IndexOutOfBoundsException();
        if (regStart + memOffs < regStart || regStart + memOffs + length >= regEnd)
            throw new RegionAddressOutOfBoundsException();

        for (int i=0; i < length; i++)
            writeByte0(regStart + memOffs + i, array[start + i]);

        if (postIncrement)
            memOffs += length;
        if (postDecrement)
            memOffs -= length;
    }

    /**
     * Reads a <code>byte</code> from the memory region at current offset. Method setOffset()
     * should be called prior calling this method to setup the offset pointer.<br>
     * Offset pointer will be modified by 1 if post-increment is enabled or -1 if
     * post-decrement is enabled.
     *
     * @exception RegionAddressOutOfBoundsException is thrown when trying to access data out of bounds
     *      of this memory region.
     */
    public int readByte() throws RegionAddressOutOfBoundsException
    {
        if (regStart + memOffs < regStart || regStart + memOffs >= regEnd)
            throw new RegionAddressOutOfBoundsException();

        int retval = readByte0(regStart + memOffs);

        if (postIncrement)
            memOffs++;
        if (postDecrement)
            memOffs--;

        return retval;
    }

    /**
     * Reads a <code>short</code> from the memory region at current offset. Method setOffset()
     * should be called prior calling this method to setup the offset pointer.<br>
     * Offset pointer will be modified by 2 if post-increment is enabled or -2 if
     * post-decrement is enabled.
     *
     * @exception RegionAddressOutOfBoundsException is thrown when trying to access data out of bounds
     *      of this memory region.
     */
    public int readShort() throws RegionAddressOutOfBoundsException
    {
        if (regStart + memOffs < regStart || regStart + memOffs >= regEnd)
            throw new RegionAddressOutOfBoundsException();

        int retval = readByte0(regStart + memOffs) << 8;
        retval |= readByte0(regStart + memOffs + 1);

        if (postIncrement)
            memOffs += 2;
        if (postDecrement)
            memOffs -= 2;

        return retval;
    }

    /**
     * Reads a <code>int</code> from the memory region at current offset. Method setOffset()
     * should be called prior calling this method to setup the offset pointer.<br>
     * Offset pointer will be modified by 4 if post-increment is enabled or -4 if
     * post-decrement is enabled.
     *
     * @exception RegionAddressOutOfBoundsException is thrown when trying to access data out of bounds
     *      of this memory region.
     */
    public int readInt() throws RegionAddressOutOfBoundsException
    {
        if (regStart + memOffs < regStart || regStart + memOffs >= regEnd)
            throw new RegionAddressOutOfBoundsException();

        int retval = readByte0(regStart + memOffs) << 24;
        retval |= readByte0(regStart + memOffs + 1) << 16;
        retval |= readByte0(regStart + memOffs + 2) << 8;
        retval |= readByte0(regStart + memOffs + 3);

        if (postIncrement)
            memOffs += 4;
        if (postDecrement)
            memOffs -= 4;

        return retval;
    }

    /**
     * Reads <code>byte</code> values from the memory starting at the current offset to the
     * destination byte array.
     * Method setOffset() should be called prior calling this method to setup the offset pointer.<br>
     * The offset pointer will be modified by number of bytes read if post-increment
     * or post-decrement flag is set.
     *
     * @param array destination byte array
     * @param start starting offset in the array
     * @param length number of bytes to read
     * @exception RegionAddressOutOfBoundsException is thrown when trying to access data out of bounds
     *      of this memory region.
     * @exception IndexOutOfBoundsException is thrown when trying to access array data that out of bounds
     *      of the destination byte array.
     */
    public void readBytes(byte[] array, int start, int length)
        throws RegionAddressOutOfBoundsException, IndexOutOfBoundsException
    {
        if (start + length > array.length)
            throw new IndexOutOfBoundsException();
        if (regStart + memOffs < regStart || regStart + memOffs + length >= regEnd)
            throw new RegionAddressOutOfBoundsException();

        for (int i=0; i < length; i++)
            array[start + i] = (byte)readByte0(regStart + memOffs + i);

        if (postIncrement)
            memOffs += length;
        if (postDecrement)
            memOffs -= length;
    }

    /**
     * Verifies if the requested meory area is valid SerialEEProm memory area.
     *
     * @param start starting address of a new memory region.
     * @param length length of a new memory region.
     * @return true if memory region validity test passes, otherwise false is returned.
     */
    protected boolean regionOk(int start, int length)
    {
        return regionOk0(start, length);
    }

    /**
     * Verifies if the requested area is valid SerialEEProm memory region.
     * @param start starting address of a new memory region.
     * @param length length of a new memory region.
     * @return true if memory region validity test passes, otherwise false is returned.
     */
    protected static native boolean regionOk0(int start, int length);

    /*
     * Native methods that write/read 8 bit values into/from serial EEProm.
     */
    protected static native boolean writeByte0(int Address, int Value);
    protected static native int readByte0(int Address);
}

